package com.smartinput.voice.application.service

import org.springframework.stereotype.Service
import org.springframework.beans.factory.annotation.Value
import org.slf4j.LoggerFactory
import java.net.URL
import java.net.HttpURLConnection
import java.io.OutputStream
import java.util.Base64
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import java.net.URI

@Service
class BaiduSpeechRecognitionService : SpeechRecognitionManager.SpeechRecognitionService {
    
    private val logger = LoggerFactory.getLogger(BaiduSpeechRecognitionService::class.java)
    private val objectMapper = ObjectMapper()
    
    @Value("\${baidu.speech.apiKey:}")
    private var apiKey: String = ""
    
    @Value("\${baidu.speech.secretKey:}")
    private var secretKey: String = ""
    
    private var accessToken: String? = null
    private var tokenExpireTime: Long = 0
    
    override val serviceName: String = "百度"
    
    override fun recognizeAudio(audioData: ByteArray): SpeechRecognitionManager.RecognitionResult {
        return try {
            // 获取访问令牌
            val token = getAccessToken()
            
            // 调用百度语音识别API
            val result = callBaiduSpeechAPI(token, audioData)
            
            SpeechRecognitionManager.RecognitionResult(
                text = result.text,
                confidence = result.confidence,
                success = result.success,
                error = result.error
            )
            
        } catch (e: Exception) {
            logger.error("百度语音识别失败", e)
            SpeechRecognitionManager.RecognitionResult(
                text = "",
                confidence = 0.0,
                success = false,
                error = e.message
            )
        }
    }
    
    private fun getAccessToken(): String {
        val currentTime = System.currentTimeMillis()
        
        // 如果令牌未过期，直接返回
        if (accessToken != null && currentTime < tokenExpireTime) {
            return accessToken!!
        }
        
        // 获取新的访问令牌
        val url = URI.create("https://aip.baidubce.com/oauth/2.0/token").toURL()
        val connection = url.openConnection() as HttpURLConnection
        
        connection.requestMethod = "POST"
        connection.doOutput = true
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
        
        val postData = "grant_type=client_credentials&client_id=$apiKey&client_secret=$secretKey"
        
        connection.outputStream.use { os ->
            os.write(postData.toByteArray())
        }
        
        val response = connection.inputStream.bufferedReader().readText()
        val tokenResponse = objectMapper.readValue<TokenResponse>(response)
        
        if (tokenResponse.access_token != null) {
            accessToken = tokenResponse.access_token
            tokenExpireTime = currentTime + (tokenResponse.expires_in * 1000) - 60000 // 提前1分钟过期
            logger.info("百度语音识别访问令牌获取成功")
        } else {
            throw RuntimeException("获取百度访问令牌失败: ${tokenResponse.error}")
        }
        
        return accessToken!!
    }
    
    private fun callBaiduSpeechAPI(accessToken: String, audioData: ByteArray): RecognitionResult {
        val url = URI.create("https://vop.baidu.com/server_api").toURL()
        val connection = url.openConnection() as HttpURLConnection
        
        connection.requestMethod = "POST"
        connection.doOutput = true
        connection.setRequestProperty("Content-Type", "application/json")
        connection.setRequestProperty("Accept", "application/json")
        
        // 准备请求数据
        val audioBase64 = Base64.getEncoder().encodeToString(audioData)
        val requestData = mapOf(
            "format" to "pcm",
            "rate" to 16000,
            "channel" to 1,
            "token" to accessToken,
            "speech" to audioBase64,
            "len" to audioData.size,
            "cuid" to "smartinput_app",
            "dev_pid" to 1537 // 普通话识别
        )
        
        val jsonRequest = objectMapper.writeValueAsString(requestData)
        
        connection.outputStream.use { os ->
            os.write(jsonRequest.toByteArray())
        }
        
        val response = connection.inputStream.bufferedReader().readText()
        val speechResponse = objectMapper.readValue<BaiduSpeechResponse>(response)
        
        return if (speechResponse.err_no == 0 && speechResponse.result.isNotEmpty()) {
            RecognitionResult(
                text = speechResponse.result[0],
                confidence = speechResponse.confidence?.get(0) ?: 0.0,
                success = true
            )
        } else {
            RecognitionResult(
                text = "",
                confidence = 0.0,
                success = false,
                error = "百度语音识别失败: ${speechResponse.err_msg}"
            )
        }
    }
    
    override fun isAvailable(): Boolean {
        return try {
            !apiKey.isBlank() && !secretKey.isBlank()
        } catch (e: Exception) {
            false
        }
    }
    
    data class RecognitionResult(
        val text: String,
        val confidence: Double,
        val success: Boolean,
        val error: String? = null
    )
    
    data class TokenResponse(
        val access_token: String?,
        val expires_in: Int,
        val error: String?
    )
    
    data class BaiduSpeechResponse(
        val err_no: Int,
        val err_msg: String,
        val result: List<String>,
        val confidence: List<Double>?
    )
} 